package com.isotronica.neveras.logica;

import java.io.IOException;
import java.io.OutputStream;
import java.sql.Date;
import java.sql.Time;
import java.util.GregorianCalendar;

import com.isotronica.neveras.logica.facades.DatosNeveraFacade;
import com.isotronica.neveras.util.dtos.DatosSensorDTO;
import com.isotronica.neveras.util.vos.DatosVO;

public class ManejoDatos {

	private static final int MASCARA_BYTE = 0xFF;

	private Controlador miComtrolador;
	private DataDecoder dataDecoder;
	private DatosNeveraFacade datosNeveraFachada;

	public ManejoDatos(DataDecoder dataDecoder) {
		this.dataDecoder = dataDecoder;
		miComtrolador = dataDecoder.getMiControlador();
		datosNeveraFachada = new DatosNeveraFacade();

	}

	public void escribirDatoDb(Time hora, Date fecha, float RH, float tem,
			byte energia, byte[] sensor, OutputStream salida, int tipo) {

		byte[] ACKT2 = new byte[0];

		int sensorInt = arr2int(sensor, 0);

		Time Dato = hora;
		Time dbTime = null;
		Date dbDate = null;

		DatosSensorDTO datosSensorDTO;

		datosSensorDTO = datosNeveraFachada.getDatosSensor(sensorInt);

		if (datosSensorDTO.getIdNevera() != 0) {

			DatosVO dato = new DatosVO();

			dato.setNevera_idNevera(datosSensorDTO.getIdNevera());
			dato.setFecha(fecha);
			dato.setHora(hora);
			dato.setTemperatura(tem);
			dato.setHumedad(RH);
			dato.setEnergia(""+energia);

			if (datosSensorDTO.isModificado()) {

				byte[] temMaxB = shortToByteArray(Float
						.floatToIntBits(datosSensorDTO.getTempMax()));
				byte[] temMinB = shortToByteArray(Float
						.floatToIntBits(datosSensorDTO.getTempMin()));
				String temTeleA = datosSensorDTO.getTelA();
				String temTeleB = datosSensorDTO.getTelB();

				String temCiudad = datosSensorDTO.getCiudad();
				String temNombre = datosSensorDTO.getNombre();

				while (temTeleA.length() < 10)
					temTeleA = "0" + temTeleA;

				while (temTeleB.length() < 10)
					temTeleB = "0" + temTeleB;

				while (temCiudad.length() < 20)
					temCiudad = "0" + temCiudad;

				while (temNombre.length() < 20)
					temNombre = "0" + temNombre;

				byte[] teleA = temTeleA.getBytes();
				byte[] teleB = temTeleB.getBytes();
				byte[] ciudad = temCiudad.getBytes();
				byte[] nombre = temNombre.getBytes();
				
				
				ACKT2 = new byte[] { 0x7E, 0x7E, sensor[0], sensor[1], 0x02,
						temMaxB[0], temMaxB[1], temMaxB[2], temMaxB[3],
						temMinB[0], temMinB[1], temMinB[2], temMinB[3],
						teleA[0], teleA[1], teleA[2], teleA[3], teleA[4],
						teleA[5], teleA[6], teleA[7], teleA[8], teleA[9],
						teleB[0], teleB[1], teleB[2], teleB[3], teleB[4],
						teleB[5], teleB[6], teleB[7], teleB[8], teleB[9],
						nombre[0], nombre[1], nombre[2], nombre[3], nombre[4],
						nombre[5], nombre[6], nombre[7], nombre[8], nombre[9],
						nombre[10], nombre[11], nombre[12], nombre[13],
						nombre[14], nombre[15], nombre[16], nombre[17],
						nombre[18], nombre[19],ciudad[0], ciudad[1], ciudad[2],
						ciudad[3], ciudad[4], ciudad[5], ciudad[6], ciudad[7],
						ciudad[8], ciudad[9], ciudad[10], ciudad[11],
						ciudad[12], ciudad[13], ciudad[14], ciudad[15],
						ciudad[16], ciudad[17], ciudad[18], ciudad[19], 0x1A };
				
				
			}

			if (datosSensorDTO.getFecha() != null) {

				dbTime = new Time(datosSensorDTO.getHora().getTime()
						+ datosSensorDTO.getFecha().getTime() - (3600000 * 5));
				dbDate = new Date(datosSensorDTO.getHora().getTime()
						+ datosSensorDTO.getFecha().getTime() - (3600000 * 5));

				if ((Dato.getTime() < new GregorianCalendar(2050, 1, 1)
						.getTime().getTime() && Dato.getTime() > (new GregorianCalendar(
						2009, 1, 1).getTime().getTime()))
						&& Dato.getTime() < (System.currentTimeMillis() + (3600000 * 0.5))) { // LA
					
					if (((Dato.getTime() > dbTime.getTime() + 390000) && tipo == 1)) { // caso
					

						
						System.out
						.println("Sensor "+sensorInt+" puesto en actulizacion " +datosNeveraFachada.actualizando(sensorInt));
						miComtrolador
						.appendText("Sensor "+sensorInt+" puesto en actulizacion " +datosNeveraFachada.actualizando(sensorInt));

						String msg = datosNeveraFachada.insertDatosTemporal(dato);
						System.out
						.println("Almacenamiento en DB Temporal "+ msg);
						miComtrolador
						.appendText("Almacenamiento en DB Temporal "+ msg);

						try {

							byte ano = Byte.valueOf(dbDate.toString()
									.substring(2, 4));
							byte mes = Byte.valueOf(dbDate.toString()
									.substring(5, 7));
							byte dia = Byte.valueOf(dbDate.toString()
									.substring(8, 10));
							byte ho = Byte.valueOf(dbTime.toString().substring(
									0, 2));
							byte min = Byte.valueOf(dbTime.toString()
									.substring(3, 5));
							byte tipot = 4;
							byte[] Actual = { 0x7E, 0x7E, sensor[0], sensor[1],
									tipot, ano, mes, dia, ho, min, 0x1A, 0x00 };

							salida.write(Actual);
							salida.flush();
							System.out
									.println("Enviada trama de retransmisión al sensor "
											+ sensorInt
											+ " \n A�o "
											+ ano
											+ " Mes "
											+ mes
											+ " Dia "
											+ dia
											+ " Hora "
											+ ho
											+ " Minuto"
											+ min
											+ "\n ");
							miComtrolador
									.appendText("Enviada trama de retransmisión al sensor "
											+ sensorInt
											+ " \n Año "
											+ ano
											+ " Mes "
											+ mes
											+ " Dia "
											+ dia
											+ " Hora "
											+ ho
											+ " Minuto"
											+ min
											+ "\n ");
						} catch (IOException e) {
							System.out
									.println("Error al retornar el ACK de retransmision, Nevera "
											+ sensorInt + "\n");
							miComtrolador
									.appendText("Error al retornar el ACK de retransmision, Nevera "
											+ sensorInt + "\n");
						}

					} else if (((Dato.getTime() > dbTime.getTime()) && tipo == 1)) {

						
						System.out
						.println("Sensor "+sensorInt+", dato a tiempo " +datosNeveraFachada.actualizado(sensorInt));
						miComtrolador
						.appendText("Sensor "+sensorInt+", dato a tiempo " +datosNeveraFachada.actualizado(sensorInt));

						String msg = datosNeveraFachada.insertDatos(dato); 
						System.out
						.println("Almacenamiento en DB "+ msg);
						miComtrolador
						.appendText("Almacenamiento en DB "+msg);
						
						try {
							if (datosSensorDTO.isModificado()) {
								salida.write(ACKT2);
								dataDecoder.setConTimeOut(0);
								System.out
										.println("Enviada trama de Atualizacion de datos al sensor "
												+ sensorInt + "\n");
								miComtrolador
										.appendText("Enviada trama de Atualizacion de datos al sensor "
												+ sensorInt + "\n");
							} else {
								byte[] ACK = { 0x7E, 0x7E, sensor[0],
										sensor[1], 0x01, 0x1A };
								salida.write(ACK);
							}

							salida.flush();
						} catch (IOException e) {
							System.out
									.println("Error Cal retornar el ACK tipo 1, Nevera "
											+ sensorInt + "/n/r");
							miComtrolador
									.appendText("Error Cal retornar el ACK tipo 1, Nevera "
											+ sensorInt);
						}

					} else if (tipo == 2 && (Dato.compareTo(dbTime) != 0)) {

						String msg = datosNeveraFachada.insertDatos(dato);
						System.out
						.println("Almacenamiento en DB"+ msg);
						miComtrolador
						.appendText("Almacenamiento en DB"+ msg);

						try {
							byte[] ACK2 = { 0x7E, 0x7E, sensor[0], sensor[1],
									0x01, 0x1A };
							salida.write(ACK2);
							salida.flush();
						} catch (IOException e) {
							System.out
									.println("Error retornando el ACK cuando esta retransmitiendo "
											+ sensorInt);
							miComtrolador
									.appendText("Error retornando el ACK cuando esta retransmitiendo "
											+ sensorInt);
						}

					} else { // dato repetido o del pasado
						try {
							byte[] ACK2 = { 0x7E, 0x7E, sensor[0], sensor[1],
									0x01, 0x1A };
							salida.write(ACK2);
							salida.flush();
						} catch (IOException e) {
							System.out.println("Error de ACK repetido "
									+ sensorInt + "/n/r");
							miComtrolador.appendText("Error de ACK repetido "
									+ sensorInt);

						}
					}

				} else {
					System.out.println("Dato fuera de fecha del sensor "
							+ sensorInt);

				}
			}else { // no hay datos en la DB

				

				byte[] ACK = { 0x7E, 0x7E, sensor[0], sensor[1], 0x01, 0x1A };
				try {
					salida.write(ACK);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}else { // No hay nevera asociada
			
			System.out.println("Sensor No asociado a Nevera  "
					+ sensorInt + "/n/r");
			miComtrolador.appendText("Sensor No asociado a Nevera  "
					+ sensorInt);

			byte[] ACK = { 0x7E, 0x7E, sensor[0], sensor[1], 0x01, 0x1A };
			try {
				salida.write(ACK);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	public static byte[] shortToByteArray(int valor) {
		byte[] resultado;
		byte b3 = (byte) ((valor >> 24) & MASCARA_BYTE);
		byte b2 = (byte) ((valor >> 16) & MASCARA_BYTE);
		byte b1 = (byte) ((valor >> 8) & MASCARA_BYTE);
		byte b0 = (byte) (valor & MASCARA_BYTE);

		resultado = new byte[] { b0, b1, b2, b3 };

		return resultado;
	}

	public static int arr2int(byte[] arr, int start) {
		int low = arr[start] & 0xff;
		int high = arr[start + 1] & 0xff;
		return (int) (high << 8 | low);
	}

	public void limpiarBandera(byte[] bytesId, OutputStream salida) {

		dataDecoder.setConTimeOut(0);
		int sensor = arr2int(bytesId, 0);
		System.out
		.println("Datos Actualizados por el Equipo "
				+ sensor);
		miComtrolador
		.appendText("Datos Actualizados por el Equipo "
				+ sensor);
		datosNeveraFachada.limpiarModificado(sensor);

	}

}
